using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Globalization;
using C4F.DevKit.WebServices.Properties;
using C4F.DevKit.WebServices.Datasets;

namespace C4F.DevKit.WebServices
{
    /// <summary>
    /// Represents search friends functionality on Myspace.com
    /// </summary>
    [ToolboxItem(true)]
    public class MySpace : C4FWebServicesBase
    {
        #region Private members

        /// <summary>
        /// Base url
        /// </summary>
        private static string baseUrl = Resources.MySpaceBaseUrl;

        #endregion

        #region Public functions

        /// <summary>
        /// The method searches for friends matching the parameter 'name'
        /// </summary>
        /// <param name="name">Name of the users to be searched</param>
        /// <returns>A list of friends matching the criteria</returns>
        public List<MySpaceUser> SearchFriends(string name)
        {
            string requestUrl = MySpace.GetQueryString(name);

            // Get MySpace response
            string responseData = base.GetQueryResponse(requestUrl);

            return MySpace.ParseResponseHtml(responseData);
        }

        /// <summary>
        /// The method searches for friends matching the parameter 'name'
        /// </summary>
        /// <param name="name">Name of the users to be searched</param>
        /// <returns>Dataset containing list of friends matching the criteria</returns>
        public DS_MySpace SearchFriends_DS(string name)
        {
            List<MySpaceUser> friends = SearchFriends(name);
            DS_MySpace dataset = new DS_MySpace();
            foreach (MySpaceUser friend in friends)
            {
                DS_MySpace.UserDetailsRow userDetailsRow = dataset.UserDetails.AddUserDetailsRow(friend.UserDetails.Headline, friend.UserDetails.Orientation, friend.UserDetails.HereFor,
                    friend.UserDetails.Gender, friend.UserDetails.Age, friend.UserDetails.Location);

                dataset.MySpaceUser.AddMySpaceUserRow(friend.Id, friend.Name, friend.ImageUrl, friend.LastProfileUpdate, userDetailsRow);
            }
            return dataset;
        }
        #endregion

        #region Private functions
        /// <summary>
        /// The method Prepares the query string based on parameters
        /// </summary>
        /// <param name="name">Name of the users to be searched</param>
        /// <returns>Request Url</returns>
        private static string GetQueryString(string name)
        {
            StringBuilder queryBuilder = new StringBuilder(MySpace.baseUrl);

            queryBuilder.Append("?fuseaction=find.search&searchType=network&interesttype=&country=&searchBy=First&f_first_name=");
            queryBuilder.Append(name);
            queryBuilder.Append("&SearchBoxID=FindAFriend");

            return queryBuilder.ToString();
        }

        /// <summary>
        /// Parses the response data and extracts the photo items
        /// </summary>
        /// <param name="responseData">Response data</param>
        /// <returns>Photo item list</returns>
        private static List<MySpaceUser> ParseResponseHtml(string responseData)
        {
            List<MySpaceUser> matchingUsers = new List<MySpaceUser>();
            // search for friendresults table in page content
            string friendResultExpression = "id=(\")?friendresults(\")?";
            Match friendResultTableMatch = Regex.Match(responseData, friendResultExpression,
                                                        RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
            // no match found. no search results were found for input name
            if (friendResultTableMatch.Success == false)
                return matchingUsers;
            // find second findpaging entry in response data
            Regex pagingRegex = new Regex("class=(\")?findpaging(\")?");
            Match pagingEndMatch = pagingRegex.Match(responseData, friendResultTableMatch.Index);

            // our matching results will lie between these two indices in repsonse data
            string tempData = responseData.Substring(friendResultTableMatch.Index, pagingEndMatch.Index - friendResultTableMatch.Index);

            int rowStartIndex = tempData.IndexOf("<tr>");

            do
            {
                int rowEndIndex = tempData.IndexOf("</tr>");
                string rowString = tempData.Substring(rowStartIndex, rowEndIndex - rowStartIndex);

                MySpaceUser mySpaceUser = new MySpaceUser();
                mySpaceUser.UserDetails = new UserDetails();

                string profileURLExpression = "(http://profile.myspace.com/index.cfm[?]fuseaction=user.viewprofile&friendID=)([0-9]*)";

                Match profileURLMatch = Regex.Match(rowString, profileURLExpression, RegexOptions.IgnoreCase);
                mySpaceUser.Id = Convert.ToInt32(profileURLMatch.Value.Substring(
                                                "http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendID=".Length), CultureInfo.InvariantCulture);

                if (rowString.IndexOf("no_pic.gif") == -1)
                {
                    // set pic url
                    string imageExpression = "(src=)(\")?";
                    Match imageMatch = Regex.Match(rowString, imageExpression, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
                    string tempURL = rowString.Substring(imageMatch.Index + imageMatch.Length,
                                                            rowString.IndexOf("/>") - imageMatch.Index - imageMatch.Length);
                    mySpaceUser.ImageUrl = tempURL.Replace("\"", string.Empty).Trim();
                }

                // remove first profile url match
                rowString = rowString.Substring(profileURLMatch.Index + profileURLMatch.Length);
                mySpaceUser.Name = rowString.Substring(0, rowString.IndexOf("</a>", StringComparison.InvariantCultureIgnoreCase));
                mySpaceUser.Name = mySpaceUser.Name.Substring(mySpaceUser.Name.LastIndexOf(">") + 1).Trim();
                // find profile url in remaining content. this match contains user name
                profileURLMatch = Regex.Match(rowString, profileURLExpression + "\"?[>]");
                //  rowString = rowString.Substring(profileURLMatch.Index + profileURLMatch.Length);


                // set headline
                mySpaceUser.UserDetails.Headline = rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length,
                                            rowString.IndexOf("<br /><strong>") - rowString.IndexOf("</strong>") - "</strong>".Length).Trim();
                if (mySpaceUser.UserDetails.Headline == "\"\"")
                    mySpaceUser.UserDetails.Headline = string.Empty;
                mySpaceUser.UserDetails.Headline = mySpaceUser.UserDetails.Headline.Replace("\"", String.Empty);

                rowString = rowString.Substring(rowString.IndexOf("<br /><strong>") + "<br /><strong>".Length);
                // set orientation
                mySpaceUser.UserDetails.Orientation = rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length,
                                            rowString.IndexOf("<br /><strong>") - rowString.IndexOf("</strong>") - "</strong>".Length).Trim();

                rowString = rowString.Substring(rowString.IndexOf("<br /><strong>") + "<br /><strong>".Length);
                // set "here for"
                mySpaceUser.UserDetails.HereFor = rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length,
                                            rowString.IndexOf("<br /><strong>") - rowString.IndexOf("</strong>") - "</strong>".Length).Trim();

                rowString = rowString.Substring(rowString.IndexOf("<br /><strong>") + "<br /><strong>".Length);
                // set gender
                mySpaceUser.UserDetails.Gender = rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length,
                                            rowString.IndexOf("<br /><strong>") - rowString.IndexOf("</strong>") - "</strong>".Length).Trim();

                rowString = rowString.Substring(rowString.IndexOf("<br /><strong>") + "<br /><strong>".Length);
                // set age

                mySpaceUser.UserDetails.Age = Convert.ToInt32(rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length,
                                            rowString.IndexOf("<br /><strong>") - rowString.IndexOf("</strong>") - "</strong>".Length).Trim(), CultureInfo.InvariantCulture);

                rowString = rowString.Substring(rowString.IndexOf("<br /><strong>") + "<br /><strong>".Length);
                // set location
                mySpaceUser.UserDetails.Location = rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length,
                                            rowString.IndexOf("<br /><strong>") - rowString.IndexOf("</strong>") - "</strong>".Length).Trim();

                rowString = rowString.Substring(rowString.IndexOf("<br /><strong>") + "<br /><strong>".Length);
                rowString = rowString.Substring(rowString.IndexOf("</strong>") + "</strong>".Length).Trim();


                mySpaceUser.LastProfileUpdate = DateTime.Parse(rowString.Substring(0, rowString.IndexOf('<')), CultureInfo.InvariantCulture);

                // add this user to matching users list
                matchingUsers.Add(mySpaceUser);

                // remove this row's data from content string
                tempData = tempData.Substring(rowEndIndex + "</tr>".Length);
                rowStartIndex = tempData.IndexOf("<tr>");
            }
            while (rowStartIndex > -1);
            return matchingUsers;
        }
        #endregion
    }

    /// <summary>
    /// Represented a user on Myspace.com
    /// </summary>
    public class MySpaceUser
    {
        #region Private Members
        /// <summary>
        /// Id of the user
        /// </summary>
        private int id;
        /// <summary>
        /// Name of the user
        /// </summary>
        private string name;
        /// <summary>
        /// Url of user's image
        /// </summary>
        private string imageUrl;
        /// <summary>
        /// Date and time when user's profile last updated
        /// </summary>
        private DateTime lastProfileUpdate;
        /// <summary>
        /// User details
        /// </summary>
        private UserDetails userDetails;
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets/Sets User's Id
        /// </summary>
        public int Id
        {
            get { return this.id; }
            set { this.id = value; }
        }
        /// <summary>
        /// Gets/Sets User's Name
        /// </summary>
        public string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }
        /// <summary>
        /// Gets/Sets User's image Url
        /// </summary>
        public string ImageUrl
        {
            get { return this.imageUrl; }
            set { this.imageUrl = value; }
        }
        /// <summary>
        /// Gets/Sets DateTime when user had last updated the profile
        /// </summary>
        public DateTime LastProfileUpdate
        {
            get { return this.lastProfileUpdate; }
            set { this.lastProfileUpdate = value; }
        }
        /// <summary>
        /// Gets/Sets User details
        /// </summary>
        public UserDetails UserDetails
        {
            get { return this.userDetails; }
            set { this.userDetails = value; }
        }
        #endregion
    }

    /// <summary>
    /// Represents the user details
    /// </summary>
    public class UserDetails
    {
        #region Private Members
        /// <summary>
        /// User's headline
        /// </summary>
        private string headline;
        /// <summary>
        /// User's Orientation
        /// </summary>
        private string orientation;
        /// <summary>
        /// Puspose of user to be on Myspace
        /// </summary>
        private string hereFor;
        /// <summary>
        /// Gender of the user
        /// </summary>
        private string gender;
        /// <summary>
        /// User's Age
        /// </summary>
        private int age;
        /// <summary>
        /// User's lacation
        /// </summary>
        private string location;
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets/Sets User's headline
        /// </summary>
        public string Headline
        {
            get { return this.headline; }
            set { this.headline = value; }
        }
        /// <summary>
        /// Gets/Sets User's Orientation informatation
        /// </summary>
        public string Orientation
        {
            get { return this.orientation; }
            set { this.orientation = value; }
        }
        /// <summary>
        /// Gets/Sets User's purpose of to be on Myspace
        /// </summary>
        public string HereFor
        {
            get { return this.hereFor; }
            set { this.hereFor = value; }
        }
        /// <summary>
        /// Gets/Sets User's gender
        /// </summary>
        public string Gender
        {
            get { return this.gender; }
            set { this.gender = value; }
        }
        /// <summary>
        /// Gets/Sets User's Age
        /// </summary>
        public int Age
        {
            get { return this.age; }
            set { this.age = value; }
        }
        /// <summary>
        /// Gets/Sets User's Location
        /// </summary>
        public string Location
        {
            get { return this.location; }
            set { this.location = value; }
        }

        #endregion
    }
}